<?php


namespace app\console;

use coco\App;

class Doc
{
    public function update(string $key='default')
    {
        $app = App::getInstance();
        $monitor_dir=$app->app_path . 'controller';

        $dir_iterator = new \RecursiveDirectoryIterator($monitor_dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS);
        $iterator = new \RecursiveIteratorIterator($dir_iterator);
        $files=[];
        foreach ($iterator as $file) {
            $blocks=[];
            if(is_dir($file))
            {
                continue;
            }
            $class='\\app\\'.str_replace([$app->app_path,'.php',DIRECTORY_SEPARATOR],['','','\\'],$file);
            if(!class_exists($class))
            {
                continue;
            }
            $ref = new \ReflectionClass($class);
            $class_key = '';
            $class_menu='';
            if($doc = $ref->getDocComment())
            {
                $class_keys = self::getDocConf($doc,'key');
                if(!empty($class_keys))
                {
                    $class_key=$class_keys[count($class_keys)-1];
                }
                $class_menus = self::getDocConf($doc,'menu');
                if(!empty($class_menus))
                {
                    $class_menu=$class_menus[count($class_menus)-1];                
                }                
            }
            if(empty($class_menu))
            {
                $class_menu=class_basename($ref->getName());
            }
            $class_file= class2url(class_basename($ref->getName()));
            $methods = $ref->getMethods();
            foreach ($methods as $method) {
                if(!$method->isPublic() || $method->isStatic())
                {
                    continue;
                }
                $doc = $method->getDocComment();
                if ($doc) {
                    $method_keys = self::getDocConf($doc,'key');
                    $method_key=!empty($method_keys)?$method_keys[count($method_keys)-1]:$class_key;
                    if($method_key !== $key)
                    {
                        continue;
                    }
                    if(!$menus = self::getDocConf($doc,'menu'))
                    {
                        continue;
                    }
                    $menu = $menus[0];
                    $paths=explode("\\",str_replace('\\app\\controller\\','',$class));
                    $paths[count($paths)-1]=class2url($paths[count($paths)-1]);
                    $api='/'.join('/',$paths).'/'.class2url($method->name);
                    $brief=self::getDocConf($doc,'brief')[0]??'';
                    $params=self::getDocConf($doc,'params');
                    $response=self::getDocConf($doc,'response');
                    $blocks[]=self::md_block($menu,$api,$brief,$params,$response);
                }
            }
            if(!empty($blocks))
            {
                $files[$class_file]=[$class_menu,$blocks];
            }
        
        }
        if(!is_dir($app->app_path.'../web/doc/'.$key))
        {
            mkdir($app->app_path.'../web/doc/'.$key,0755,true);
        }
        self::xCopy(dirname(__FILE__).'/../doc',$app->app_path.'../web/doc/'.$key);  
        $sidebar=['* [首页](/)'];
        foreach($files as $file=>$md)
        {
            list($class_menu,$blocks)=$md;
            $sidebar[]='* ['.$class_menu.']('.$file.')';
            file_put_contents($app->app_path.'../web/doc/'.$key.'/'.$file.'.md',join("\n\n",$blocks));
        }
        file_put_contents($app->app_path.'../web/doc/'.$key.'/_sidebar.md',join("\n",$sidebar));
        file_put_contents($app->app_path.'../web/doc/'.$key.'/README.md',file_get_contents(file_exists($app->app_path . 'controller/coco-doc-'.$key.'.md')?$app->app_path . 'controller/coco-doc-'.$key.'.md':$app->app_path.'../web/doc/'.$key.'/_sidebar.md'));
    }
    private static function getDocConf(string $doc , string $name){
        $rows=explode(PHP_EOL,$doc);
        $vals=[];
        foreach($rows as $row)
        {
            $key='@coco-'.$name;
            if(false!==$pos=strpos($row,$key))
            {
                $vals[]=trim(substr($row,$pos + strlen($key)));
            }
        }
        return $vals;
    }

    private static function md_block(string $menu ,string $api, string $brief, array $params , array $response){
        $bolck="#### $menu\n\n>请求地址 `$api`\n\n";
        if(!empty($brief))
        {
            $bolck.=">$brief\n\n";
        }
        $bolck.="\n\n";
        if(!empty($params))
        {
            $bolck.=" **参数说明** \n\n| 参数 | 类型 | 必填 | 默认值 | 含义 |\n| ------------ | ------------ | ------------ | ------------ | ------------ |\n";
            $bolck.=join("\n",$params)."\n\n";
        }
        if(!empty($response))
        {
            $bolck.=" **返回参数说明** \n\n| 参数 | 类型  | 含义 |\n| ------------ | ------------ | ------------ |\n";
            $bolck.=join("\n",$response)."\n\n";
        }
        
        return $bolck;
    }
    private static function xCopy($source, $destination){
        
        //参数说明：
        // $source:源目录名
        // $destination:目的目录名
        if(!is_dir($destination)){
            mkdir($destination,0755);
        }
        $handle=dir($source);
        while($entry=$handle->read()) {
            if(($entry!=".")&&($entry!="..")){
                if(is_dir($source."/".$entry)){
                    self::xCopy($source."/".$entry,$destination."/".$entry);
                }
                else{
                    copy($source."/".$entry,$destination."/".$entry);
                }
            }
        }
    }
}